# Rsbuild Instance

This section describes all the properties and methods on the Rsbuild instance object.

## rsbuild.context

`rsbuild.context` is a read-only object that provides some context infos.

### context.version

The version of `@rsbuild/core` currently in use.

- **Type:**

```ts
type Version = string;
```

### context.rootPath

The root path of current build, corresponding to the `cwd` option of [createRsbuild](/api/javascript-api/core#creatersbuild) method.

- **Type:**

```ts
type RootPath = string;
```

### context.distPath

The absolute path of the output directory, corresponding to the [output.distPath.root](/config/output/dist-path) config in `RsbuildConfig`.

When there are multiple environments, Rsbuild will try to get the parent distPath of all environments as `context.distPath`.

If you want to get the absolute path to the output directory of a specified environment, it is recommended to use [environment.distPath](/api/javascript-api/environment-api#distpath).

- **Type:**

```ts
type DistPath = string;
```

### context.cachePath

The absolute path of the build cache files.

- **Type:**

```ts
type CachePath = string;
```

### context.devServer

Dev server information, including the current dev server hostname and port number.

- **Type:**

```ts
type DevServer = {
  hostname: string;
  port: number;
};
```

### context.bundlerType

The bundler type of current build.

- **Type:**

```ts
type bundlerType = 'rspack' | 'webpack';
```

> Rsbuild internally supports switching to webpack for comparative testing, so this field is provided for differentiation. Usually, you do not need to use this field.

## rsbuild.build

Perform a production mode build.

- **Type:**

```ts
type BuildOptions = {
  /**
   * Whether to watch for file changes and rebuild.
   * @default false
   */
  watch?: boolean;
  /**
   * Using a custom Rspack Compiler object.
   */
  compiler?: Compiler | MultiCompiler;
};

function Build(options?: BuildOptions): Promise<{
  /**
   * Rspack's [stats](https://rspack.dev/api/javascript-api/stats) object.
   */
  stats?: Rspack.Stats | Rspack.MultiStats;
  /**
   * Stop watching when in watch mode.
   */
  close: () => Promise<void>;
}>;
```

- **Example:**

```ts
import { logger } from '@rsbuild/core';

// Example 1: run build
await rsbuild.build();

// Example 2: build and handle the error
try {
  await rsbuild.build();
} catch (err) {
  logger.error('Failed to build.');
  logger.error(err);
  process.exit(1);
}

// Example 3: build and get all stats
const { stats } = await rsbuild.build();

if (stats) {
  const { assets } = stats.toJson({ assets: true });
  console.log(assets);
}
```

### Monitor file changes

If you need to watch file changes and re-build, you can set the `watch` option to `true`.

```ts
await rsbuild.build({
  watch: true,
});
```

In watch mode, the `rsbuild.build()` returns a `close` method, which can be used to stop watching:

```ts
const result = await rsbuild.build({
  watch: true,
});

await result.close();
```

### Stats Object

In non-watch mode, the `rsbuild.build() returns an Rspack [stats](https://rspack.dev/api/javascript-api/stats) object:

```ts
const result = await rsbuild.build();

console.log(result.stats);
```

### Custom Compiler

In some cases, you may want to use a custom compiler:

```ts
import { rspack } from '@rsbuild/core';

const compiler = rspack({
  // ...
});
await rsbuild.build({
  compiler,
});
```

## rsbuild.startDevServer

Start the local dev server.

- **Type:**

```ts
type StartDevServerOptions = {
  /**
   * Using a custom Rspack Compiler object.
   */
  compiler?: Compiler | MultiCompiler;
  /**
   * Whether to get port silently and not print any logs.
   * @default false
   */
  getPortSilently?: boolean;
};

type StartServerResult = {
  urls: string[];
  port: number;
  server: Server;
};

function StartDevServer(
  options?: StartDevServerOptions,
): Promise<StartServerResult>;
```

- **Example:**

Start dev server:

```ts
import { logger } from '@rsbuild/core';

// Start dev server
await rsbuild.startDevServer();

// Start dev server and handle the error
try {
  await rsbuild.startDevServer();
} catch (err) {
  logger.error('Failed to start dev server.');
  logger.error(err);
  process.exit(1);
}
```

After successfully starting dev server, you can see the following logs:

```
  ➜ Local:    http://localhost:3000
  ➜ Network:  http://192.168.0.1:3000
```

`startDevServer` returns the following parameters:

- `urls`: URLs to access dev server.
- `port`: The actual listening port number.
- `server`: Server instance object.

```ts
const { urls, port, server } = await rsbuild.startDevServer();
console.log(urls); // ['http://localhost:3000', 'http://192.168.0.1:3000']
console.log(port); // 3000

// Close the dev server
await server.close();
```

### Custom Compiler

In some cases, you may want to use a custom compiler:

```ts
import { rspack } from '@rsbuild/core';

const compiler = rspack({
  // ...
});
await rsbuild.startDevServer({
  compiler,
});
```

### Get Port Silently

In some cases, the default startup port number is already occupied. In this situation, Rsbuild will automatically increment the port number until it finds an available one. This process will output a prompt log. If you do not want this log, you can set `getPortSilently` to `true`.

```ts
await rsbuild.startDevServer({
  getPortSilently: true,
});
```

## rsbuild.createDevServer

Rsbuild comes with a built-in dev server designed to improve the development experience. When you run the `rsbuild dev` command, the server will start, providing features such as page preview, routing, and hot module reloading.

If you want to integrate Rsbuild dev server into an custom server, you can use this method to get the instance methods of dev server and call them on demand.

- **Type:**

```ts
type EnvironmentAPI = {
  [name: string]: {
    /**
     * Get stats info about current environment.
     */
    getStats: () => Promise<Stats>;
    /**
     * Load and execute stats bundle in server.
     *
     * @param entryName - relate to Rsbuild's `source.entry`
     * @returns the return value of entry module.
     */
    loadBundle: <T = unknown>(entryName: string) => Promise<T>;
    /**
     * Get the compiled HTML template.
     */
    getTransformedHtml: (entryName: string) => Promise<string>;
  };
};

type RsbuildDevServer = {
  /**
   * Listen the Rsbuild server.
   * Do not call this method if you are using a custom server.
   */
  listen: () => Promise<{
    port: number;
    urls: string[];
    server: {
      close: () => Promise<void>;
    };
  }>;
  /**
   * Environment API of Rsbuild server.
   */
  environments: EnvironmentAPI;
  /**
   * The resolved port.
   * By default, Rsbuild server listens on port `3000` and automatically increments the port number if the port is occupied.
   */
  port: number;
  /**
   * The `connect` app instance.
   * Can be used to attach custom middlewares to the dev server.
   */
  middlewares: Connect.Server;
  /**
   * Notify that the Rsbuild server has been started.
   * Rsbuild will trigger `onAfterStartDevServer` hook in this stage.
   */
  afterListen: () => Promise<void>;
  /**
   * Activate socket connection.
   * This ensures that HMR works properly.
   */
  connectWebSocket: (options: { server: HTTPServer }) => void;
  /**
   * Close the Rsbuild server.
   */
  close: () => Promise<void>;
  /**
   * Print the server URLs.
   */
  printUrls: () => void;
  /**
   * Open URL in the browser after starting the server.
   */
  open: () => Promise<void>;
};

type CreateDevServerOptions = {
  /**
   * Using a custom Rspack Compiler object.
   */
  compiler?: Compiler | MultiCompiler;
  /**
   * Whether to get port silently and not print any logs.
   * @default false
   */
  getPortSilently?: boolean;
  /**
   * Whether to trigger Rsbuild compilation
   * @default true
   */
  runCompile?: boolean;
};

function CreateDevServer(
  options?: CreateDevServerOptions,
): Promise<RsbuildDevServer>;
```

- **Example:**

Here is an example with [express](https://expressjs.com/):

```ts
import { createRsbuild } from '@rsbuild/core';
import express from 'express';

export async function startDevServer() {
  // Init Rsbuild
  const rsbuild = await createRsbuild({});

  const app = express();

  // Create Rsbuild DevServer instance
  const rsbuildServer = await rsbuild.createDevServer();

  // Apply Rsbuild’s built-in middlewares
  app.use(rsbuildServer.middlewares);

  const httpServer = app.listen(rsbuildServer.port, async () => {
    // Notify Rsbuild that the custom server has started
    await rsbuildServer.afterListen();
  });

  rsbuildServer.connectWebSocket({ server: httpServer });
}
```

For detailed usage, please refer to: [Example](https://github.com/rspack-contrib/rspack-examples/blob/main/rsbuild/express/server.mjs).

If you want to use Rsbuild DevServer to start the project directly, you can use the [Rsbuild - startDevServer](#rsbuildstartdevserver) method directly. `startDevServer` is actually syntactic sugar for the following code:

```ts
const server = await rsbuild.createDevServer();

await server.listen();
```

### connectWebSocket

Rsbuild has a builtin WebSocket handler to support HMR:

1. When a user accesses a page through browser, a WebSocket connection request is automatically initiated to the server.
2. After the Rsbuild dev server detects the connection request, it instructs the builtin WebSocket handler to process it.
3. After the browser successfully establishes a connection with the Rsbuild WebSocket handler, real-time communication is possible.
4. The Rsbuild WebSocket handler notifies the browser after each recompilation is complete. The browser then sends a `hot-update.(js|json)` request to the dev server to load the new compiled module.

When you use custom server, you may encounter HMR connection error problems. This is because the custom server does not forward WebSocket connection requests to Rsbuild's WebSocket handler.

At this time, you need to use the `connectWebSocket` method to enable Rsbuild to sense and process the WebSocket connection request from the browser.

```ts
const rsbuildServer = await rsbuild.createDevServer();

const httpServer = app.listen(rsbuildServer.port);

rsbuildServer.connectWebSocket({ server: httpServer });
```

## rsbuild.preview

Start a server to preview the production build locally. This method should be executed after [rsbuild.build](#rsbuildbuild).

- **Type:**

```ts
type PreviewOptions = {
  /**
   * Whether to get port silently
   * @default false
   */
  getPortSilently?: boolean;
  /**
   * Whether to check if the dist directory exists and is not empty.
   * @default true
   */
  checkDistDir?: boolean;
};

type StartServerResult = {
  urls: string[];
  port: number;
  server: {
    close: () => Promise<void>;
  };
};

function preview(options?: PreviewOptions): Promise<StartServerResult>;
```

- **Example:**

Start the server:

```ts
import { logger } from '@rsbuild/core';

// Start preview server
await rsbuild.preview();

// Start preview server and handle the error
try {
  await rsbuild.preview();
} catch (err) {
  logger.error('Failed to start preview server.');
  logger.error(err);
  process.exit(1);
}
```

`preview` returns the following parameters:

- `urls`: URLs to access server.
- `port`: The actual listening port number.
- `server`: Server instance object.

```ts
const { urls, port, server } = await rsbuild.preview();
console.log(urls); // ['http://localhost:3000', 'http://192.168.0.1:3000']
console.log(port); // 3000

// Close the server
await server.close();
```

## rsbuild.createCompiler

Create an Rspack [Compiler](https://rspack.dev/api/javascript-api/compiler) instance. If there are multiple [environments](/config/environments) for this build, the return value is `MultiCompiler`.

- **Type:**

```ts
function CreateCompiler(): Promise<Compiler | MultiCompiler>;
```

- **Example:**

```ts
const compiler = await rsbuild.createCompiler();
```

> You do not need to use this API unless you need to custom the dev server or other advanced scenarios.

## rsbuild.addPlugins

Register one or more Rsbuild plugins, which can be called multiple times.

This method needs to be called before compiling. If it is called after compiling, it will not affect the compilation result.

- **Type:**

```ts
type AddPluginsOptions = { before?: string; environment?: string };

function AddPlugins(
  plugins: Array<RsbuildPlugin | Falsy>,
  options?: AddPluginsOptions,
): void;
```

- **Example:**

```ts
rsbuild.addPlugins([pluginFoo(), pluginBar()]);

// Insert before the bar plugin
rsbuild.addPlugins([pluginFoo()], { before: 'bar' });

// Add plugin for node environment
rsbuild.addPlugins([pluginFoo()], { environment: 'node' });
```

## rsbuild.getPlugins

Get all the Rsbuild plugins registered in the current Rsbuild instance.

- **Type:**

```ts
function GetPlugins(): RsbuildPlugin[];
```

- **Example:**

```ts
console.log(rsbuild.getPlugins());
```

## rsbuild.removePlugins

Removes one or more Rsbuild plugins, which can be called multiple times.

This method needs to be called before compiling. If it is called after compiling, it will not affect the compilation result.

- **Type:**

```ts
function RemovePlugins(pluginNames: string[]): void;
```

- **Example:**

```ts
// add plugin
const pluginFoo = pluginFoo();
rsbuild.addPlugins(pluginFoo);

// remove plugin
rsbuild.removePlugins([pluginFoo.name]);
```

## rsbuild.isPluginExists

import IsPluginExists from '@en/shared/isPluginExists.mdx';

<IsPluginExists />

- **Example:**

```ts
rsbuild.addPlugins([pluginFoo()]);

rsbuild.isPluginExists(pluginFoo().name); // true
```

## rsbuild.initConfigs

The initConfigs method is used to initialize the internal configs of Rsbuild and return the Rspack config generated internally by Rsbuild.

Usually, you do not need to call the initConfigs method, because it will be automatically called when methods such as [rsbuild.build](#rsbuildbuild), [rsbuild.startDevServer](#rsbuildstartdevserver) are called.

- **Type:**

```ts
function InitConfigs(): Promise<{
  rspackConfigs: Rspack.Configuration[];
}>;
```

- **Example:**

```ts
const { rspackConfigs } = await rsbuild.initConfigs();

console.log(rspackConfigs);
```

## rsbuild.inspectConfig

The inspectConfig method is typically used for debugging the internal configuration of Rsbuild. It returns the internally generated Rsbuild config and Rspack config, serializes them into strings, and supports writing them to the disk.

If you need to view the Rsbuild and Rspack configurations during the build process, you can use [debug mode](/guide/debug/debug-mode), or obtain them through hooks such as [onBeforeBuild](#rsbuildonbeforebuild), [onBeforeCreateCompile](#rsbuildonbeforecreatecompiler).

- **Type:**

```ts
type InspectConfigOptions = {
  // View the config in the specified environment
  // defaults to "development", can be set to "production"
  mode?: RsbuildMode;
  // Whether to enable verbose mode, display the complete content of the function in the config
  // defaults to `false`
  verbose?: boolean;
  // Specify the output path
  // defaults to the value of `output.distPath.root`
  outputPath?: string;
  // Whether to write the result to disk
  // defaults to `false`
  writeToDisk?: boolean;
};

async function InspectConfig(options?: InspectConfigOptions): Promise<{
  rsbuildConfig: string;
  bundlerConfigs: string[];
  environmentConfigs: string[];
  origin: {
    rsbuildConfig: RsbuildConfig;
    environmentConfigs: Record<string, EnvironmentConfig>;
    bundlerConfigs: BundlerConfigs[];
  };
}>;
```

### Example

Get the content of configs in string format:

```ts
const { rsbuildConfig, bundlerConfigs } = await rsbuild.inspectConfig();

console.log(rsbuildConfig, bundlerConfigs);
```

Write the config content to disk:

```ts
await rsbuild.inspectConfig({
  writeToDisk: true,
});
```

### Output Path

You can set the output path using `outputPath`. The default value is [output.distPath.root](/config/output/dist-path).

If `outputPath` is a relative path, it will be concatenated relative to the value of `output.distPath.root`. You can also set `outputPath` to an absolute path, in which case the files will be written directly to that path. For example:

```ts
import path from 'node:path';

await rsbuild.inspectConfig({
  writeToDisk: true,
  outputPath: path.join(__dirname, 'custom-dir'),
});
```

## rsbuild.onBeforeCreateCompiler

import OnBeforeCreateCompiler from '@en/shared/onBeforeCreateCompiler.mdx';

<OnBeforeCreateCompiler />

- **Example:**

```ts
rsbuild.onBeforeCreateCompiler(({ bundlerConfigs }) => {
  console.log('the Rspack config is ', bundlerConfigs);
});
```

## rsbuild.onAfterCreateCompiler

import OnAfterCreateCompiler from '@en/shared/onAfterCreateCompiler.mdx';

<OnAfterCreateCompiler />

- **Example:**

```ts
rsbuild.onAfterCreateCompiler(({ compiler }) => {
  console.log('the compiler is ', compiler);
});
```

## rsbuild.onBeforeBuild

import OnBeforeBuild from '@en/shared/onBeforeBuild.mdx';

<OnBeforeBuild />

- **Example:**

```ts
rsbuild.onBeforeBuild(({ bundlerConfigs }) => {
  console.log('the Rspack config is ', bundlerConfigs);
});
```

## rsbuild.onAfterBuild

import OnAfterBuild from '@en/shared/onAfterBuild.mdx';

<OnAfterBuild />

- **Example:**

```ts
rsbuild.onAfterBuild(({ stats }) => {
  console.log(stats?.toJson());
});
```

## rsbuild.onCloseBuild

import OnCloseBuild from '@en/shared/onCloseBuild.mdx';

<OnCloseBuild />

- **Example:**

```ts
rsbuild.onCloseBuild(async () => {
  console.log('close build!');
});
```

## rsbuild.onBeforeStartDevServer

import OnBeforeStartDevServer from '@en/shared/onBeforeStartDevServer.mdx';

<OnBeforeStartDevServer />

- **Example:**

```ts
rsbuild.onBeforeStartDevServer(() => {
  console.log('before start!');
});
```

## rsbuild.onAfterStartDevServer

import OnAfterStartDevServer from '@en/shared/onAfterStartDevServer.mdx';

<OnAfterStartDevServer />

- **Example:**

```ts
rsbuild.onAfterStartDevServer(({ port, routes }) => {
  console.log('this port is: ', port);
  console.log('this routes is: ', routes);
});
```

## rsbuild.onCloseDevServer

import OnCloseDevServer from '@en/shared/onCloseDevServer.mdx';

<OnCloseDevServer />

- **Example:**

```ts
rsbuild.onCloseDevServer(async () => {
  console.log('close dev server!');
});
```

## rsbuild.onBeforeStartProdServer

import OnBeforeStartProdServer from '@en/shared/onBeforeStartProdServer.mdx';

<OnBeforeStartProdServer />

- **Example:**

```ts
rsbuild.onBeforeStartProdServer(() => {
  console.log('before start!');
});
```

## rsbuild.onAfterStartProdServer

import OnAfterStartProdServer from '@en/shared/onAfterStartProdServer.mdx';

<OnAfterStartProdServer />

- **Example:**

```ts
rsbuild.onAfterStartProdServer(({ port, routes }) => {
  console.log('this port is: ', port);
  console.log('this routes is: ', routes);
});
```

## rsbuild.onDevCompileDone

import OnDevCompileDone from '@en/shared/onDevCompileDone.mdx';

<OnDevCompileDone />

- **Example:**

```ts
rsbuild.onDevCompileDone(({ isFirstCompile }) => {
  if (isFirstCompile) {
    console.log('first compile!');
  } else {
    console.log('re-compile!');
  }
});
```

## rsbuild.onExit

import OnExit from '@en/shared/onExit.mdx';

<OnExit />

- **Example:**

```ts
rsbuild.onExit(() => {
  console.log('exit!');
});
```

## rsbuild.getRsbuildConfig

import GetRsbuildConfig from '@en/shared/getRsbuildConfig.mdx';

<GetRsbuildConfig />

- **Example:**

```ts
rsbuild.onBeforeBuild(() => {
  const config = rsbuild.getRsbuildConfig();
  console.log(config.html?.title);
});
```

## rsbuild.getNormalizedConfig

import GetNormalizedConfig from '@en/shared/getNormalizedConfig.mdx';

<GetNormalizedConfig />

- **Example:**

```ts
rsbuild.onBeforeBuild(() => {
  const config = api.getNormalizedConfig();
  console.log(config.html.title);
});
```
